<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" charset="utf-8"/>
<style>
div,h1,h2,input,button,a,p{
  padding: 0;
  margin: 0;
}
body{
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
}
div{
text-align:center;
border: 1px solid #000;
}

</style>
<title>SUDOKU</title>
</head>
<body onload="sudokuDisplay();">
</body>
<script type="text/javascript" charset="utf-8">
var drawForm = function(){
  var h1 = document.createElement("h1");
  h1.style.textAlign = "center";
  h1.innerHTML="SUDOKU";
  document.body.appendChild(h1);
  var p = document.createElement("p");
  p.style.textAlign = "center";
  p.innerHTML="You can make it! Good luck!.";
  document.body.appendChild(p);
}
var drawMain = function(){
  var ruler = document.body.clientWidth;
	if(!document.getElementById("mDiv")){
	    var mDiv = document.createElement("div");
	    mDiv.id = "mDiv";
	    mDiv.style.width = "329px";
	    mDiv.style.height = "329px";
	    mDiv.style.margin = "5px auto";
      mDiv.style.padding = "0px";
	    mDiv.style.left = "0px";
	    mDiv.style.right = "0px";
	    document.body.appendChild(mDiv);
	}
}

var drawSlave = function(){
  for(var i = 0;i < 9;i += 1){
	  if(!document.getElementById("sDiv"+i)){
	    var sDiv = document.createElement("div");
	    sDiv.id = "sDiv"+i;
	    sDiv.style.width = "102px";
	    sDiv.style.height = "102px";
      sDiv.style.padding = "0px";
	    sDiv.style.margin = "5px 0px 0px 5px";
      sDiv.style.float = "left";
	    mDiv.appendChild(sDiv);
			}
	}
}

var drawMin = function(){
    for(i = 0;i < 9;i += 1){
	    for(j = 0;j < 9;j += 1){
	      if(!document.getElementById("cDiv"+(i*9+j))){
	        var cDiv = document.createElement("div");
          cDiv.setAttribute("lock","on");
          cDiv.setAttribute("value","");
	        cDiv.id = "cDiv"+(i*9+j);
	        cDiv.style.width = "34px";
	        cDiv.style.height = "34px";
          cDiv.style.lineHeight = "30px";
          cDiv.style.border = "none";
	        cDiv.style.float = "left";
          if ((i*9+j)%2 === 1) {
            cDiv.style.background="rgb(200,200,200)";
          }
          var id = parseInt(j/3)+parseInt(i/3)*3;
	        document.getElementById("sDiv"+id).appendChild(cDiv);
          cDiv.onclick = function(){
          for(var k =0;k < 9;k += 1){
            if(document.getElementById("buttonDiv"+k).style.background==="gray")break;
          }
            if(k===9){alert("请选择一个答案");
            }
            else {
              var lock = this.getAttributeNode("lock").value;
              if (lock ==="on") {
                this.innerHTML="";
                var sudoku = new Array;
                for (var i = 0; i < 9; i += 1){
                  sudoku[i] = new Array();
                    for(var j = 0;j < 9;j += 1){
                      getDiv = parseInt(document.getElementById("cDiv"+(i*9+j)).innerHTML);
                      if (isNaN(getDiv)){getDiv=0;}
                      sudoku[i][j]= getDiv;
                    }
                }
                var row = parseInt(parseInt(this.id.replace(/[^0-9]/ig,""))/9);
                var col = parseInt(this.id.replace(/[^0-9]/ig,""))%9;
                if (checkBox(sudoku,row,col,k+1)) {
                  this.style.color = "green";
                }
                else {
                  this.style.color = "red";
                }
                this.innerHTML = k+1;
              }
            }
          }
	      }
	  }
  }
}

var drawControlpal = function(){
  var ruler = document.body.clientWidth;
  if(!document.getElementById("ctrlDiv")){
      var ctrlDiv = document.createElement("div");
      ctrlDiv.id = "ctrlDiv";
      ctrlDiv.style.width = "329px";
      ctrlDiv.style.height = "34px";
      ctrlDiv.style.margin = "5px auto";
      ctrlDiv.style.left = "0px";
      ctrlDiv.style.right = "0px";
      document.body.appendChild(ctrlDiv);
      for(var i =0;i < 9;i += 1){
	        if(!document.getElementById("buttonDiv"+i)){
	            var buttonDiv = document.createElement("div");
	            buttonDiv.id = "buttonDiv"+i;
	            buttonDiv.style.width = "30px";
	            buttonDiv.style.height = "30px";
              buttonDiv.style.lineHeight = "30px";
	            buttonDiv.style.float = "left";
	            buttonDiv.style.margin = "1px 0px 0px 4.5px";
	            ctrlDiv.appendChild(buttonDiv);
              buttonDiv.innerHTML=i+1;
              buttonDiv.onclick = function(){
                  for(var j =0;j < 9;j += 1){
                    document.getElementById("buttonDiv"+j).style.background="white";
                    document.getElementById("buttonDiv"+j).style.color="black";
                  }
              this.style.background="gray";
              this.style.color="white";
              }
			}
		}
  }
  if(!document.getElementById("resetButton")){
      var reset = document.createElement("button");
      reset.id="resetButton";
      reset.onclick=function(){sudokuDisplay();}
      reset.style.position = "absolute";
      reset.style.width="100px";
      reset.style.height="32px";
      reset.style.margin = "10px auto";
      reset.style.left = "0px";
      reset.style.right = "0px";
      reset.innerHTML="Reset";
      document.body.appendChild(reset);
  }
}

var sudokuCreate = function(){
  var sudoku = new Array;
  for (var i = 0; i < 9; i += 1){
    sudoku[i] = new Array();
      for(var j = 0;j < 9;j += 1){
        sudoku[i][j]= 0;
      }
  }
  var cDiv = 0;
	var sDiv = 0;
	var row = 0;
	var col = 0;
	var num = 0;
	var check = false;
	var calculateTime = 0;
	for (num = 1;num < 10;num += 1){//顺序选择填入1~9数字
		for (sDiv = 0;sDiv < 9;sDiv += 1){//顺序选择填入slave单元
        cDiv = Math.ceil(Math.random()*8);//随机选一个填入空格
  			row = parseInt(cDiv/3)+3*(parseInt(sDiv/3));
  			col = cDiv%3+3*(sDiv%3);
        check = checkBox(sudoku,row,col,num);//检查填入数合法否
        while (sudoku[row][col]!=0||!check) {	//如果填入数不合法，换下一个位置填入
					cDiv += 1;
					calculateTime += 1;
					if(calculateTime > 9){//如果尝试超过9次，说明本次尝试无解并重置
						calculateTime = 0;
						num = 1;
						sDiv = 0;
						calculateTime += 1;
            for (var i = 0; i < 9; i += 1){
							sudoku[i] = new Array();
								for(var j = 0;j < 9;j += 1){
									sudoku[i][j]= 0;
								}
						}
					}
					if(cDiv > 8){
						cDiv = 0;
					}
          row = parseInt(cDiv/3)+3*(parseInt(sDiv/3));
    			col = cDiv%3+3*(sDiv%3);
				  check = checkBox(sudoku,row,col,num);//重新检测
      }
    calculateTime = 0;
    sudoku[row][col] = num;//本次填入合法，记录本次填入
		}
  }
  return(sudoku);
}

var checkBox = function (sudoku,row,col,num){//检查填入数字是否合法
    for(var i = 0;i < 9;i += 1){
      //是否同行重复
      if(i!=row && sudoku[i][col] === num){
        return false;
      }
      //是否同列重复
      if(i!=col && sudoku[row][i] === num){
        return false;
      }
      //是否同单元重复
      var x=parseInt(row/3)*3+parseInt(i/3);
      var y=parseInt(col/3)*3+i%3;
      if(sudoku[x][y]===num){
        if (x===col && y===row) {
          continue;
        }
        return false;
      }
    }
  return true;
  }
  var checkBoxx = function (sudoku,row,col,num){//检查填入数字是否合法
      for(var i = 0;i < 9;i += 1){
        //是否同行重复
        if(i!=row && sudoku[i][col] === num){
          return false;
        }
        //是否同列重复
        if(i!=col && sudoku[row][i] === num){
          return false;
        }
        //是否同单元重复
        /*var x=parseInt(row/3)*3+parseInt(i/3);
        var y=parseInt(col/3)*3+i%3;
        if(sudoku[x][y]===num){
          if (x===col && y===row) {
            continue;
          }
          return false;
        }*/
      }
    return true;
    }

var solveBox = function (sudoku) {//解数独
  var holeMap = new Array();
  var puzzle = new Array();
  for (var i = 0; i < 9; i++) {
    puzzle[i] = new Array();
    for (var j = 0; j < 9; j++) {
      puzzle[i][j] = sudoku[i][j];
      if (sudoku[i][j]===0) {
        holeMap.push(i*9+j);
      }
    }
  }
  var solving = function(sudoku,num,i){
    if (i >= holeMap.length) {
      return(true);
    }
    if (i === -1) {
      return(false);
    }
      if (num === 10){
        if (i===0) {
          return(false);
        }
        var row = parseInt(holeMap[i]/9);
        var col = holeMap[i]%9;
        sudoku[row][col] = 0;
        var row = parseInt(holeMap[i-1]/9);
        var col = holeMap[i-1]%9;
        return function(){
            return(solving(sudoku,sudoku[row][col]+1,i-1));//回溯
        }
      }
      var row = parseInt(holeMap[i]/9);
      var col = holeMap[i]%9;
      var check = checkBox(sudoku,row,col,num)
      if (check) {
        sudoku[row][col] = num;
        return function(){
            return(solving(sudoku,1,i+1));
        }
      }
      else{
        return function(){
            return(solving(sudoku,num+1,i));
        }
      }
    }
  return(solving(puzzle,1,0));
}

var puzzleCreate = function(sudoku){
  for (var i = 0; i < 9; i++) {
    for (var j = 0; j < 9; j++) {
      if (sudoku[i][j]===0) {
        continue;
      }
      if (digCondition(sudoku,i,j)&&solveCondition(sudoku,i,j)) {
          sudoku[i][j]=0;
      }
      else {
          continue;
      }
    }
  }
  return(sudoku);
}


var solveCondition = function(sudoku,row,col){//解唯一约束
  var temp = sudoku[row][col];
  for (var i = 1; i < 10; i++) {
    if(i === temp)continue;
    sudoku[row][col] = i;
    if (checkBoxx(sudoku,row,col,i)&&solveBox(sudoku)) {
      sudoku[row][col] = temp;
      return false
    }
    else {
        continue;
    }
  }
  sudoku[row][col] = temp;
  return true;
}

var digCondition = function(sudoku,row,col){//挖洞数目约束
    var rowCheck = 0;
    var colCheck = 0;
    var globalCheck = 0;
    var slaveCheck = 0;
    for (var i = 0; i < 9; i++) {
        if (sudoku[i][col]===0) {//每行不超过5个洞
          rowCheck += 1;
          if (rowCheck > 6) {
            return false;
          }
        }
        if (sudoku[row][i]===0) {//每列不超过5个洞
          colCheck += 1;
          if (colCheck > 6) {
            return false;
          }
        }
        for (var j = 0; j < 9; j++) {
          if (sudoku[i][j]===0) {//全局不超过50个洞
            globalCheck += 1;
            if (globalCheck > 50) {
              return false;
            }
          }
        }
    }
    return true;
  }

var insertSudoku = function(){
  var sudoku = sudokuCreate();
  var puzzle = new Array();
  for (var i = 0; i < 9; i++) {
    puzzle[i] = new Array();
    for (var j = 0; j < 9; j++) {
      puzzle[i][j] = sudoku[i][j];
    }
  }
  var puzzle = puzzleCreate(puzzle);
  for(var i = 0;i < 9;i += 1){
		for(var j = 0;j < 9;j += 1){
		    var	cDiv = document.getElementById("cDiv"+(i*9+j));
        cDiv.setAttribute("value",sudoku[i][j]);
        if (puzzle[i][j]!=0) {
          cDiv.innerHTML = puzzle[i][j];
          cDiv.setAttribute("lock","off");
        }
		}
	}
}

var sudokuDisplay = function(){
  document.body.innerHTML = "";
  drawForm();
//绘制主框架
  drawMain();
//绘制从框架
  drawSlave();
//绘制最小单元
  drawMin();
//绘制控制单元
  drawControlpal();
//生成最终解并填入框架
  insertSudoku();
}
</script>
</html>
